//
//把ALU控制和ALU合并，为了将就溢出检测
//溢出检测在ADD，ADDi，SUB中检测

module ALU(
    input [31:0] rs,  //也作为访存指令中的base
    input [31:0] rt,
    input [4:0] sa,   // ins[10:6] of R type    
    input [2:0] ALUop,
    input [5:0] FuncCode,
    output reg [31:0] rd,  //more generally, it is just ALUout
    output wire Zero, 
    output reg overflow
);

//这里溢出还需要解决，ADD和ADDi以及Sub都需要解决溢出
//不写入问题，如何控制溢出的信号？

reg [3:0] ALUCtl;

assign Zero = (rd==0); //zero is true if rd is 0

//Generate ALUCtl by ALUop form Control unit
always @(*)begin
case(ALUop)
   3'b000,3'b111:  ALUCtl <= 4'b0010;   // add   
   3'b001:  ALUCtl <= 4'b0110;   // sub
   3'b010:begin                  // R type
          case(FuncCode)
          6'b100000,6'b100001: ALUCtl <= 4'b0010;   // add
          6'b100010: ALUCtl <= 4'b0110;   // sub
          6'b100100: ALUCtl <= 4'b0000;   // and
          6'b100101: ALUCtl <= 4'b0001;   // or
          6'b100110: ALUCtl <= 4'b0100;   // xor
          6'b100111: ALUCtl <= 4'b1100;   // nor
          6'b101010: ALUCtl <= 4'b0111;   // slt
          6'b000000: ALUCtl <= 4'b0011;   // sll
          6'b000010: ALUCtl <= 4'b1000;   // srl
          default: ALUCtl <= 4'b1111;     // should not happen 
          endcase
   end
   3'b011: ALUCtl <= 4'b0001;   // or
   3'b100: ALUCtl <= 4'b0000;   // and
   3'b101: ALUCtl <= 4'b0100;   // xor
   3'b110: ALUCtl <= 4'b1110;   //lui
   default: ALUCtl <= 4'b1111;     // should not happen 
endcase
end

always @(*) begin
    case (ALUCtl)
    4'b0000: rd <= rs & rt;  //and
    4'b0001: rd <= rs | rt;  //or
    4'b0010: rd <= rs + rt;  //add
    4'b0100: rd <= rs ^ rt;  //xor
    4'b0110: rd <= rs - rt;  //sub
    4'b0111: rd <= rs < rt? 1:0;  //is ture if rs is smaller
    4'b1100: rd <= ~(rs | rt);    //result is nor
    4'b0011: rd <= rt << sa;      // left shift sa bit
    4'b1000: rd <= rt >> sa;      // right shift sa bit
    4'b1110: rd <= {rt[15:0],16'b0}; // Lui instruction
    default: rd <= 0;
    endcase
end

always@(*)begin
    case(ALUop)
    3'b010:begin
        case(FuncCode)
        6'b100000: overflow <= rd[31] ^ rd[30];   // add
        6'b100010: overflow <= rd[31] ^ rd[30];   // sub
        default: overflow <= 1'b0;
        endcase
    end
    3'b111: overflow <= rd[31] ^ rd[30];   //addi
    default:overflow <= 1'b0;
    endcase
end
endmodule














/*
module ALUControl(
    input [2:0] ALUop,
    input [5:0] FuncCode,
    output reg [3:0] ALUCtl
);
always @(*)begin
case(ALUop)
   3'b000:  ALUCtl <= 4'b0010;   // add
   3'b001:  ALUCtl <= 4'b0110;   // sub
   3'b010:begin                  // R type
          case(FuncCode)
          6'b100000: ALUCtl <= 4'b0010;   // add
          6'b100010: ALUCtl <= 4'b0110;   // sub
          6'b100100: ALUCtl <= 4'b0000;   // and
          6'b100101: ALUCtl <= 4'b0001;   // or
          6'b100110: ALUCtl <= 4'b0100;   // xor
          6'b100111: ALUCtl <= 4'b1100;   // nor
          6'b101010: ALUCtl <= 4'b0111;   // slt
          6'b000000: ALUCtl <= 4'b0111;   // sll
          6'b000010: ALUCtl <= 4'b1000;   // srl
          default: ALUCtl <= 4'b1111;     // should not happen 
          endcase
   end
   3'b011: ALUCtl <= 4'b0001;   // or
   3'b100: ALUCtl <= 4'b0000;   // and
   3'b101: ALUCtl <= 4'b0100;   // xor
   3'b110: ALUCtl <= 4'b1110;   //lui
   default: ALUCtl <= 4'b1111;     // should not happen 
endcase
end
endmodule
*/